#ifndef __NETWORK_PLAY_H__
#define __NETWORK_PLAY_H__

#include "Player.hpp"
#include "KeyHandle.hpp"
#include "BlackChess.hpp"
#include "WhiteChess.hpp"
#include "ChessBoard.hpp"

class Point
{
public:
	Point() {}
	Point(int x, int y) :x(x), y(y) {}
	int getX() const
	{
		return x;
	}
	int getY() const
	{
		return y;
	}
private:
	int x;
	int y;
};

class NetworkPlayer :public Player
{
public:
	NetworkPlayer(const string& name, const string& color, KeyHandle* keyHandle, string ip, string port, bool localUser = false) :Player(name, color),
		keyHandle(keyHandle),
		localUser(localUser)
	{
		// 初始化 Winsock
		WSADATA ws;
		if (WSAStartup(MAKEWORD(2, 2), &ws) != 0) {
			perror("WSAStartup failed.");
			return;
		}

		sockfd = socket(AF_INET, SOCK_DGRAM, 0);
		if (sockfd == INVALID_SOCKET)
		{
			perror("Fail to socket");
			return;
		}

		if (localUser)
		{
			this->peerIP = ip;
			this->peerPort = port;
		}
		else
		{
			sockaddr_in service;
			service.sin_family = AF_INET;
			service.sin_port = htons(atoi(port.c_str()));
			service.sin_addr.S_un.S_addr = inet_addr(ip.c_str());
			int ret = ::bind(sockfd, (sockaddr*)&service, sizeof(service));
			if (ret < 0)
			{
				perror("Fail to bind");
				return;
			}
		}
	}

	~NetworkPlayer()
	{
		closesocket(sockfd);
	}

	bool recvPointFromPeer(Point& point)
	{
		int ret = recvfrom(sockfd, (char*)&point, sizeof(point), 0, NULL, NULL);
		if (ret <= 0)
		{
			perror("Fail to recv");
			return false;
		}
		return true;
	}

	bool transPointToPeer(const Point& point, const string& ip, const string& port)
	{
		sockaddr_in service;
		service.sin_family = AF_INET;
		service.sin_port = htons(atoi(port.c_str()));
		service.sin_addr.S_un.S_addr = inet_addr(ip.c_str());
		int ret = sendto(sockfd, (const char*)&point, sizeof(point), 0, (const sockaddr*)&service, sizeof(service));
		if (ret < 0)
		{
			perror("Fail to send");
			return false;
		}
		return true;
	}

	bool placeChess(int x, int y)
	{
		ChessBoard* chessBoard = ChessBoard::getChessBoard();
		bool canPlace = chessBoard->isVaildPos(x, y);
		if (canPlace)
		{
			Chess* chess = nullptr;
			if (getColor() == "white")
			{
				chess = new WhiteChess(x, y);
			}
			else
			{
				chess = new BlackChess(x, y);
			}
			chessBoard->placeChess(chess);
			return true;
		}
		return false;
	}

	void waitPlaceChess()
	{
		if (!localUser)
		{
			Point point;
			bool ok = recvPointFromPeer(point);
			if (ok)
			{
				keyHandle->setCursorPos(point.getX(), point.getY());
				this->placeChess(point.getX(), point.getY());
			}
		}
		else
		{
			keyHandle->waitPlayerPlaceChess(this);
			this->transPointToPeer(Point(keyHandle->getCursorX(), keyHandle->getCursorY()), peerIP, peerPort);
		}
	}

private:
	int sockfd;
	bool localUser;
	string peerIP;
	string peerPort;
	KeyHandle* keyHandle;
};

#endif // !__NETWORK_PLAY_H__